
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:reabampos/objectbox.g.dart';
import 'package:reabampos/src/reabam/operation/bean/api_download_db_file_url.dart';
import 'package:reabampos/src/reabam/operation/bean/bean_goodtype.dart';
import 'package:reabampos/src/reabam/operation/bean/bean_paytype.dart';
import 'package:reabampos/src/reabam/operation/db/models.dart';
import 'package:reabampos/src/reabam/operation/db/models_cuxiao.dart';
import 'package:reabampos/src/reabam/operation/db/objectbox.dart';
import 'package:reabampos/src/reabam/operation/rb_api.dart';
import 'package:reabampos/src/reabam/operation/rb_config.dart';
import 'package:reabampos/src/reabam/ui/pagestate_main_webview.dart';
import 'package:xsdk_flutter/xsdk/xsdk_flutter_package.dart';

/*
下载离线数据
 */
abstract class SupportDownloadDBFile{

  //h5调用原生方法通知获取返回的离线数据文件下载路径,载离线数据
  static void downloadOfflineDBFileUrl(
      dynamic data,
      XFunctionResultCallback callback
      ){
    Map<String,dynamic> resultCallback={};


    String companyId=XSharePreferencesUtils.getString(RBConfigs.SP_companyId);

    Map<String,dynamic> urlMap;
    if(data is String){
      urlMap=XJsonUtils.json2Map(data);
    }else{
      urlMap=data??{};
    }

    String url=urlMap['url']??'';
    String zipUrl=urlMap['zipUrl']??'';
    int version=int.tryParse('${urlMap['version']??'0'}')??0;

    XLogUtils.printLog('---开始下载支付方式,version=$version');
    //1.下载支付方式
    resultCallback['code']='200';
    resultCallback['type']=1;
    callback(resultCallback);

    RBBaseApi.payList(
      equipmentIdentity:RBConfigs.isShangMiDevice?"sumipay":null,
      failed: (String code, String msg) {
        XLogUtils.printLog('---下载支付方式失败: code:$code,msg=$msg');
        //通知h5下载离线数据失败
        resultCallback['code']='-1';
        callback(resultCallback);
      },
      succeed: (PayTypeResponse response, Map<String, dynamic> responseMap1, Map<String, dynamic> headersResponse) {
        //
        dynamic DataLine1=responseMap1['DataLine'];
        //保存支付方式
        XSharePreferencesUtils.saveString(RBConfigs.SP_Pos_OfflineDB_payType+companyId, XJsonUtils.obj2Json(DataLine1));

        //2.下载商品分类
        XLogUtils.printLog('---开始下载商品分类');
        resultCallback['code']='200';
        resultCallback['type']=2;
        callback(resultCallback);

        RBBaseApi.goodTypeList(
            optType:'2',
            filterType: 'Order',
            failed: (String code,String msg){
              XLogUtils.printLog('---下载商品分类失败: code:$code,msg=$msg');
              //通知h5下载离线数据失败
              resultCallback['code']='-1';
              callback(resultCallback);
            },
            succeed: (GoodTypeResponse response, Map<String,dynamic> responseMap,Map<String, dynamic> headersResponse) async {
              //保存商品分类
              dynamic DataLine=responseMap['DataLine'];
              String pTypeJson=XJsonUtils.obj2Json(DataLine);
              XSharePreferencesUtils.saveString('${RBConfigs.SP_Pos_OfflineDB_goodsType}$companyId',pTypeJson);
              XLogUtils.printLog('---保存商品分类pTypeJson=$pTypeJson');

              //3.判断数据版本,下载离线数据
              int oldVersion=XSharePreferencesUtils.getInt(RBConfigs.SP_offlineDBGoodsVersion2+companyId,defaultValue: -1);
              //version=0; //test

              if(version==0 || version>oldVersion){

                //开始下载离线文件
                resultCallback['code']='200';
                resultCallback['type']=3;
                callback(resultCallback);

                bool isSucceedDownload=false;
                //init
                XSharePreferencesUtils.saveBool(RBConfigs.SP_Pos_Save_OfflineFile_To_DB_Succeed+companyId,false);
                XSharePreferencesUtils.saveBool(RBConfigs.SP_Pos_CompanyId_Save_DB_Succeed+companyId,false);
                //
                String fileName="GoodItemsDB_$companyId";
                String filePath='${XTempData.appDocumentsDirectoryPath}/$fileName';
                XLogUtils.printLog('---filePath=$filePath');
                //删除旧文件
                XFileUtils.deleteFile(filePath);

                String zipfileName="GoodItemsDBZip_$companyId";
                String zipfilePath='${XTempData.appDocumentsDirectoryPath}/$zipfileName';
                XFileUtils.deleteFile(zipfilePath);

                //
                XLogUtils.printLog('---开始下载离线数据文件');

                //3.1优先下载压缩数据
                if(!XStringUtils.isEmpty(zipUrl)){

                  Response downloadResponse= await XHttpUtils.download_sync(
                    url: zipUrl,
                    savePath: zipfilePath,
                  );
                  XLogUtils.printLog('---压缩文件下载完成');
                  //完成下载,解压
                  try{
                    isSucceedDownload=XCompressUtils.uncompressOfGZip(
                        zipFilePath: zipfilePath,
                        outFilePath: filePath
                    );
                  }catch(e){
                    XLogUtils.printLog('---解压文件失败:$e');
                  }

                }

                if(!isSucceedDownload){
                  //3.2下载非压缩数据文件
                  Response downloadResponse= await XHttpUtils.download_sync(
                    url: url,
                    savePath: filePath,
                  );
                  XLogUtils.printLog('---非压缩文件下载完成');
                  isSucceedDownload=true;
                }


                //4.处理下载文件
                XLogUtils.printLog('---isSucceedDownload=$isSucceedDownload');
                if (isSucceedDownload){

                  Future(() async {
                    resultCallback['code']='200';
                    resultCallback['type']=4;
                    callback(resultCallback);

                    XObjectBoxUtils.store?.runInTransaction(TxMode.write,()  {

                      //4.1.清除旧数据库,兼容旧版,删除所有商品数据,否则逐行对比版本
                      if (version==0){
                        XObjectBoxUtils.shelfTimeBox?.removeAll();
                        XObjectBoxUtils.goodBox?.removeAll();
                        XObjectBoxUtils.goodSpecBox?.removeAll();

                      }else{
                        //判断存在少于version的删除
                        if(XObjectBoxUtils.goodBox==null){
                          XLogUtils.printLog('---XObjectBoxUtils.goodBox==null');
                          return;
                        }else{
                          XLogUtils.printLog('---XObjectBoxUtils.goodBox!=null');
                        }

                        Query<BeanOfflineDBGood> queryBeanofflinedbgoods1=XObjectBoxUtils.goodBox!
                            .query(BeanOfflineDBGood_.version.lessThan(version))
                            .build();
                        List<BeanOfflineDBGood> listLess=queryBeanofflinedbgoods1.find();
                        queryBeanofflinedbgoods1.close();

                        if (listLess.isNotEmpty){
                          List<int> ids=[];
                          for(BeanOfflineDBGood detail in listLess){
                            ids.add(detail.id);
                            // if(detail.shelfTime.isNotEmpty){
                            //   detail.shelfTime.clear();
                            // }
                          }
                          XObjectBoxUtils.goodBox!.removeMany(ids);

                          //删除规格
                          Query<BeanOfflineDBGoodSpec> queryBeanofflinedbgoodsSpec1=XObjectBoxUtils.goodSpecBox!
                              .query(BeanOfflineDBGoodSpec_.version.lessThan(version))
                              .build();
                          List<BeanOfflineDBGoodSpec> listSpecLess=queryBeanofflinedbgoodsSpec1.find();
                          queryBeanofflinedbgoodsSpec1.close();

                          if(listSpecLess.isNotEmpty){
                            List<int> ids1=[];
                            for(BeanOfflineDBGoodSpec detail in listSpecLess){
                              ids1.add(detail.id);
                            }
                            XObjectBoxUtils.goodSpecBox!.removeMany(ids1);
                          }

                        }
                      }

                      //4.2读取文件
                      XLogUtils.printLog('---开始读取离线数据文件');

                      List<String> lines =  File(filePath).readAsLinesSync();

                      _saveToDB(lines,version);

                      //5.完成写入数据库
                      XLogUtils.printLog('---写入商品数据完成');
                      //XLogUtils.printLog('---查找数据库count=${XObjectBoxUtils.goodBox?.count()}');
                      XSharePreferencesUtils.saveString("XDownloadLastTimeReabamPos_DB$companyId", XDateUtils.getCurrentTime_String(format: XDateUtils.formatTimeDefault2));
                      XSharePreferencesUtils.saveBool(RBConfigs.SP_Pos_Save_OfflineFile_To_DB_Succeed+companyId,true);
                      XSharePreferencesUtils.saveBool(RBConfigs.SP_Pos_CompanyId_Save_DB_Succeed+companyId,true);

                      //保存全量商品版本
                      XSharePreferencesUtils.saveInt(RBConfigs.SP_offlineDBGoodsVersion2+companyId,version);

                      //6.通知h5下载数据完成
                      resultCallback['code']='200';
                      resultCallback['type']=10;
                      callback(resultCallback);

                    });

                  });


                }else{
                  //通知h5下载离线数据失败
                  resultCallback['code']='-1';
                  callback(resultCallback);
                }

              }else{
                XLogUtils.printLog('---没有新版本的商品数据,忽略下载');
                resultCallback['code']='200';
                resultCallback['type']=10;
                callback(resultCallback);
              }

            }
        );


      },
    );

  }


  //websocket通知h5商品增量更新
  static void h5webSocketUpdateGoodItemsDB(XPageState statePage,dynamic data){

    Future((){

      try{
        String companyId=XSharePreferencesUtils.getString(RBConfigs.SP_companyId);

        BeanOfflineUpdateGoodItems beanOfflineUpdateItem;
        if(data is String){
          beanOfflineUpdateItem=BeanOfflineUpdateGoodItems.fromJson(XJsonUtils.json2Map(data));
        }else{
          beanOfflineUpdateItem=BeanOfflineUpdateGoodItems.fromJson(data??{});
        }

        String type=beanOfflineUpdateItem.type??'';

        XLogUtils.printLog('---开始下载商品分类');
        RBBaseApi.goodTypeList(
            optType:'2',
            filterType: 'Order',
            failed: (String code,String msg){
              XLogUtils.printLog('---下载商品分类失败: code:$code,msg=$msg');
              //通知h5下载离线数据失败
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('h5webSocketUpdateGoodItemsDB','false'));
              }
            },
            succeed: (GoodTypeResponse response, Map<String,dynamic> responseMap,Map<String, dynamic> headersResponse) async {
              //保存商品分类
              dynamic DataLine=responseMap['DataLine'];
              String pTypeJson=XJsonUtils.obj2Json(DataLine);
              XSharePreferencesUtils.saveString('${RBConfigs.SP_Pos_OfflineDB_goodsType}$companyId',pTypeJson);
              XLogUtils.printLog('---保存商品分类pTypeJson=$pTypeJson');

              //更新增量数据
              if ("DELETE"==type){
                //删除
                _updateGoodItems_del(statePage,beanOfflineUpdateItem.itemIds??[],int.tryParse('${beanOfflineUpdateItem.version}')??0);
              }else{
                //新增,修改
                _update_goods_by_ItemIds(statePage,beanOfflineUpdateItem.itemIds??[]);
              }

            }
        );

      }catch(e){
        //
      }

    });

  }
  //h5调用原生方法下载全量促销, 过期旧方法,新促销下载废弃,兼容旧版
  static void downloadOfflineDBPromotionFileUrl(XPageState statePage,dynamic data){

    try{
      BeanOfflineFileUrl_promotion beanItem;
      if(data is String){
        beanItem=BeanOfflineFileUrl_promotion.fromJson(XJsonUtils.json2Map(data));
      }else{
        beanItem=BeanOfflineFileUrl_promotion.fromJson(data??{});
      }

      //2023.4.20 downLoadUrls为空则表示没有促销数据,清除相关数据表
      List<dynamic>? downLoadUrls=beanItem.downLoadUrls;
      int dataVersion=int.tryParse('${beanItem.dataVersion}')??0;

      String companyId=XSharePreferencesUtils.getString(RBConfigs.SP_companyId);
      //旧版本
      int oldVersion=XSharePreferencesUtils.getInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,defaultValue: -1);

      if(dataVersion>oldVersion){
        _downFile_cuxiao_2(statePage,downLoadUrls,dataVersion,companyId);
        return;
      }

      XLogUtils.printLog("---没有最新版本的促销数据,忽略下载");
      if(statePage is MainWebViewStatePage){
        statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','true'));
      }
    }catch(e){
      //
      XLogUtils.printLog("---downloadOfflineDBPromotionFileUrl,e:$e");
    }

  }
  //websocket通知h5促销增量或全量更新
  static void h5webSocketUpdatePromotion(XPageState statePage,dynamic data){

    try{
      BeanWebsocketPromotionUpdate beanWebsocketPromotionUpdate;
      if(data is String){
        beanWebsocketPromotionUpdate=BeanWebsocketPromotionUpdate.fromJson(XJsonUtils.json2Map(data));
      }else{
        beanWebsocketPromotionUpdate=BeanWebsocketPromotionUpdate.fromJson(data??{});
      }

      String companyId=XSharePreferencesUtils.getString(RBConfigs.SP_companyId);

      String action=beanWebsocketPromotionUpdate.action??'';
      if(action.contains("fast/promotion/update")){
        //增量促销(单促销)
        String projectId=beanWebsocketPromotionUpdate.projectId??'';

        RBBaseApi.checkPromotion1(
            projectId: projectId,
            succeed: (Response_websocket_promotion response, Map<String, dynamic> responseMap, Map<String, dynamic> headersResponse) {
              BeanOfflineFileUrl_promotion? data=response.data;

              if (data!=null){

                //2023.4.20 downLoadUrls为空则表示没有促销数据,清除相关数据表
                List<dynamic>? downLoadUrls=data.downLoadUrls;
                int dataVersion=int.tryParse('${data.dataVersion}')??0;
                //各个增量版本记录
                String versionListJson=XSharePreferencesUtils.getString(RBConfigs.SP_offlineDBCuXiaoVersion_zl_list+companyId);
                List<dynamic> versionList=XJsonUtils.json2List(versionListJson);

                //不在已下载记录的增量版本号内
                if(!versionList.contains('$dataVersion')){
                  _downFile_cuxiao_1(statePage,projectId,downLoadUrls,dataVersion,companyId);
                  return;
                }
              }

              XLogUtils.printLog("---没有最新版本的促销数据,忽略下载");
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','true'));
              }
            },
            failed: (String code, String msg) {
              statePage.toast(msg);
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
              }
            });



      }else{
        //全量促销下载

        RBBaseApi.checkPromotion2(
            succeed: (Response_websocket_promotion response, Map<String, dynamic> responseMap, Map<String, dynamic> headersResponse) {
              BeanOfflineFileUrl_promotion? data=response.data;

              if (data!=null){

                //2023.4.20 downLoadUrls为空则表示没有促销数据,清除相关数据表
                List<dynamic>? downLoadUrls=data.downLoadUrls;
                int dataVersion=int.tryParse('${data.dataVersion}')??0;
                //旧版本
                int oldVersion=XSharePreferencesUtils.getInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,defaultValue: -1);

                if(dataVersion>oldVersion){
                  _downFile_cuxiao_2(statePage,downLoadUrls,dataVersion,companyId);
                  return;
                }
              }

              XLogUtils.printLog("---没有最新版本的促销数据,忽略下载");
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','true'));
              }
            },
            failed: (String code, String msg) {
              statePage.toast(msg);
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
              }

            });

      }



    }catch(e){
      //
      XLogUtils.printLog("---h5webSocketUpdatePromotion,e:$e");
    }


  }


  ////////////////////////////////////////////////////

  /*
    下载增量促销
    适配增量不按版本顺序情况(补增量)
     */
  static void _downFile_cuxiao_1(XPageState statePage,String projectId, List<dynamic>? urls, int version, String companyId){


    Future(() async{
      try{

        //
        if(urls==null || urls.isEmpty){
          /*
                    如何处理促销方案失效(停用)？
                    解决方案：
                    1、找到方案(pjId)所有促销规则id(planIds)。
                    2、删除方案
                    3、循环planIds，判断其他方案是否用存在该planid？有忽略，没有则代表规则已经失效，清空促销规则相关的表数据。
                     */

          //0.判断是否有projectId高版本增量
          Query<DbCXPromotion> queryDbcxpromotionHigh=XObjectBoxUtils.box_DbCXPromotion!.query(
              DbCXPromotion_.projectId.equals(projectId).and(DbCXPromotion_.version.greaterOrEqual(version))
          ).build();
          List<DbCXPromotion> listDbcxpromotionHigh=queryDbcxpromotionHigh.find();
          queryDbcxpromotionHigh.close();
          if(listDbcxpromotionHigh.isNotEmpty){
            //存在,则不处理,以最新版未准 ok
          }else{
            //不存在,则更新删除

            //1.新增一条空白的方案表示该最高版本
            DbCXPromotion newDbCXPromotion=DbCXPromotion();
            newDbCXPromotion.version=version;
            newDbCXPromotion.projectId=projectId;
            newDbCXPromotion.planId="";
            XObjectBoxUtils.box_DbCXPromotion!.put(newDbCXPromotion);

            //2.清除多余数据
            _handleDbCXPromotionOldVersion(projectId,XObjectBoxUtils.box_DbCXPromotion!,XObjectBoxUtils.box_DbCXItemTimed!,XObjectBoxUtils.box_DBCXOrderProduct!,XObjectBoxUtils.box_DbCXProduct!,XObjectBoxUtils.box_DbCXSuitBom!,XObjectBoxUtils.box_DbCXMutexPlan!,version);

          }

        }else{
          //增量或修改,下载促销离线数据

          //0.判断是否有projectId高版本增量
          Query<DbCXPromotion> queryDbcxpromotionHigh=XObjectBoxUtils.box_DbCXPromotion!.query(
              DbCXPromotion_.projectId.equals(projectId).and(DbCXPromotion_.version.greaterOrEqual(version))
          ).build();
          List<DbCXPromotion> listDbcxpromotionHigh=queryDbcxpromotionHigh.find();
          queryDbcxpromotionHigh.close();
          if(listDbcxpromotionHigh.isNotEmpty){
            //存在,则不处理,以最新版未准 ok
            XLogUtils.printLog("---存在高版本则不处理,以最新版未准");
          }else {
            //不存在,则添加
            String baseFileName="CuxiaoDB_add_${companyId}_";


            for(int i=0;i<urls.length;i++){
              String filePath='${XTempData.appDocumentsDirectoryPath}/$baseFileName$i';
              //删除旧文件
              XFileUtils.deleteFile(filePath);

              bool isSucceedDownload = false;

              Response downloadResponse= await XHttpUtils.download_sync(
                url: '${urls[i]}',
                savePath: filePath,
              );
              isSucceedDownload=true;

              XLogUtils.printLog("---下载促销文件= $i, isSucceedDownload=$isSucceedDownload");

              if(!isSucceedDownload){
                //失败
                if(statePage is MainWebViewStatePage){
                  statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
                }
                return;
              }else{
                //成功
                //1.读取文件
                final int fileIndex=i;

                try{

                  List<String> fileLines=await File(filePath).readAsLines();

                  String dataType = "";
                  while(fileLines.isNotEmpty) {
                    String line = fileLines.removeAt(0);
                    XLogUtils.printLog('---fileIndex=$fileIndex, 增量line=$line');

                    //2.写入数据库
                    if (!XStringUtils.isEmpty(line)){

                      if("promotions begin"==line){
                        dataType="promotions";
                      }else if("itemBomProducts begin"==line){
                        dataType="itemBomProducts";
                      }else if("products begin"==line){
                        dataType="products";
                      }else if("itemTimeds begin"==line){
                        dataType="itemTimeds";
                      }else if("orderProducts begin"==line){
                        dataType="orderProducts";
                      }else if("suitBoms begin"==line){
                        dataType="suitBoms";
                      }else if("mutexPlans begin"==line){
                        dataType="mutexPlans";
                      }else if(!line.startsWith("{") && line.contains("end")){
                        dataType="";
                      }else if(line.startsWith("{")){
                        Map<String, dynamic> mapItem = XJsonUtils.json2Map(line);

                        if("promotions"==dataType){
                          DbCXPromotion item=DbCXPromotion();
                          item.planId= '${mapItem['planId']}';
                          item.projectId= '${mapItem['projectId']}';
                          item.promotionJson= mapItem['promotionJson']??'';
                          item.beginDate= '${mapItem['beginDate']}';
                          item.endDate='${mapItem['endDate']}';
                          item.planType= '${mapItem['planType']}';
                          item.version=version;

                          XObjectBoxUtils.box_DbCXPromotion!.put(item);

                        }else if("itemBomProducts"==dataType){
                          DbCXItemBomProduct item=DbCXItemBomProduct();
                          item.bomId= '${mapItem['bomId']}';
                          item.giftMustQty= '${mapItem['giftMustQty']??'0'}';
                          item.giftMustSel= '${mapItem['giftMustSel']??'0'}';
                          item.itemId= '${mapItem['itemId']}';
                          item.specId= '${mapItem['specId']}';
                          item.version=version;

                          //判断商品规格表是否存在,存在则添加,否则查无商品
                          Query<BeanOfflineDBGoodSpec> querySpec=XObjectBoxUtils.goodSpecBox!
                              .query(BeanOfflineDBGoodSpec_.specId.equals(item.specId!))
                              .build();
                          List<BeanOfflineDBGoodSpec> listSpec=querySpec.find();
                          if(listSpec.isNotEmpty){
                            XObjectBoxUtils.box_DbCXItemBomProduct!.put(item);
                          }
                          querySpec.close();

                        }else if("products"==dataType){

                          //适用增量更新,因此平铺planid
                          List<dynamic> planIds=mapItem['planIds']??[];
                          Set<String> setPlanid={};
                          for(dynamic iitem in planIds){
                            setPlanid.add('$iitem');
                          }

                          for(String planid in setPlanid){
                            DbCXProduct item=DbCXProduct();
                            item.excl= mapItem['excl']??false;
                            item.planIdEach=planid;
                            item.productType= '${mapItem['productType']}';
                            item.typeId= '${mapItem['typeId']}';
                            item.parentId= '${mapItem['parentId']}';
                            item.version=version;
                            XObjectBoxUtils.box_DbCXProduct!.put(item);
                          }

                        }else if("itemTimeds"==dataType){
                          DbCXItemTimed item=DbCXItemTimed();
                          item.itemId= '${mapItem['itemId']}';
                          item.leftLimitNumPerDay= '${mapItem['leftLimitNumPerDay']}';
                          item.leftTotalLimitNum= '${mapItem['leftTotalLimitNum']}';
                          item.limitNumPerDay= '${mapItem['limitNumPerDay']}';
                          item.limitPurchases= '${mapItem['limitPurchases']}';
                          item.planId= '${mapItem['planId']}';
                          item.specId= '${mapItem['specId']}';
                          item.specialPrice= '${mapItem['specialPrice']}';
                          item.totalLimitNum='${mapItem['totalLimitNum']}';
                          item.version=version;

                          XObjectBoxUtils.box_DbCXItemTimed!.put(item);

                        }else if("orderProducts"==dataType){
                          DBCXOrderProduct item=DBCXOrderProduct();
                          item.excl= mapItem['excl']??false;
                          item.planId= '${mapItem['planId']}';
                          item.productType= '${mapItem['productType']}';
                          item.typeId= '${mapItem['typeId']}';
                          item.parentId= '${mapItem['parentId']}';
                          item.version=version;

                          XObjectBoxUtils.box_DBCXOrderProduct!.put(item);

                        }else if("suitBoms"==dataType){
                          DbCXSuitBom item=DbCXSuitBom();
                          item.planId= '${mapItem['planId']}';
                          item.bomId= '${mapItem['bomId']}';
                          item.version=version;

                          XObjectBoxUtils.box_DbCXSuitBom!.put(item);
                        }else if("mutexPlans"==dataType){
                          DbCXMutexPlan item=DbCXMutexPlan();
                          item.planId= '${mapItem['planId']}';
                          item.mutexPlanId= '${mapItem['mutexPlanId']}';
                          item.version=version;
                          XObjectBoxUtils.box_DbCXMutexPlan!.put(item);
                        }
                      }
                    }

                  }

                }catch (e){
                  XLogUtils.printLog('---写入报错:$e');
                  if(statePage is MainWebViewStatePage){
                    statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
                  }

                  return;
                }
                XLogUtils.printLog("---成功写入促销: $fileIndex");
              }
            }

            //清除多余数据
            _handleDbCXPromotionOldVersion(projectId,XObjectBoxUtils.box_DbCXPromotion!,XObjectBoxUtils.box_DbCXItemTimed!,XObjectBoxUtils.box_DBCXOrderProduct!,XObjectBoxUtils.box_DbCXProduct!,XObjectBoxUtils.box_DbCXSuitBom!,XObjectBoxUtils.box_DbCXMutexPlan!,version);

          }

        }


        //6.成功完成通知
        XLogUtils.printLog("---离线促销数据处理完成通知");
        //各个增量版本记录
        String versionListJson=XSharePreferencesUtils.getString(RBConfigs.SP_offlineDBCuXiaoVersion_zl_list+companyId);
        List<dynamic> versionList=XJsonUtils.json2List(versionListJson);
        versionList.add("$version");
        XSharePreferencesUtils.saveString(RBConfigs.SP_offlineDBCuXiaoVersion_zl_list+companyId,XJsonUtils.obj2Json(versionList));
        //
        if(statePage is MainWebViewStatePage){
          statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','true'));
        }

      }catch(e){
        //
        XLogUtils.printLog("---_downFile_cuxiao_1,e:$e");
      }
    });
  }
  /*
    下载全量促销
    步骤:
    全量更新时，低于当前版本号的促销数据清空。
     */
  static void _downFile_cuxiao_2(XPageState statePage,List<dynamic>? urls, int version,String companyId){


    Future(() async {
      try{
        //
        XLogUtils.printLog('---开始下载促销');

        //1.查找比当前版本高的数据
        Query<DbCXItemBomProduct> queryDbcxitembomproduct=XObjectBoxUtils.box_DbCXItemBomProduct!.query(
            DbCXItemBomProduct_.version.greaterThan(version)
        ).build();
        List<DbCXItemBomProduct> listDbcxitembomproductV=queryDbcxitembomproduct.find();
        queryDbcxitembomproduct.close();
        if(listDbcxitembomproductV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxitembomproductV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxitembomproductV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxitembomproductV.add(DbCXItemBomProduct.fromJson(item1));
          }
        }

        Query<DbCXItemTimed> queryDbcxitemtimed=XObjectBoxUtils.box_DbCXItemTimed!.query(
            DbCXItemTimed_.version.greaterThan(version)
        ).build();
        List<DbCXItemTimed> listDbcxitemtimedV=queryDbcxitemtimed.find();
        queryDbcxitemtimed.close();
        if(listDbcxitemtimedV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxitemtimedV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxitemtimedV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxitemtimedV.add(DbCXItemTimed.fromJson(item1));
          }
        }

        Query<DBCXOrderProduct> queryDbcxorderproduct=XObjectBoxUtils.box_DBCXOrderProduct!.query(
            DBCXOrderProduct_.version.greaterThan(version)
        ).build();
        List<DBCXOrderProduct> listDbcxorderproductV=queryDbcxorderproduct.find();
        queryDbcxorderproduct.close();
        if(listDbcxorderproductV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxorderproductV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxorderproductV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxorderproductV.add(DBCXOrderProduct.fromJson(item1));
          }
        }

        Query<DbCXProduct> queryDbcxproduct=XObjectBoxUtils.box_DbCXProduct!.query(
            DbCXProduct_.version.greaterThan(version)
        ).build();
        List<DbCXProduct> listDbcxproductV=queryDbcxproduct.find();
        queryDbcxproduct.close();
        if(listDbcxproductV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxproductV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxproductV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxproductV.add(DbCXProduct.fromJson(item1));
          }
        }

        Query<DbCXPromotion> queryDbcxpromotion=XObjectBoxUtils.box_DbCXPromotion!.query(
            DbCXPromotion_.version.greaterThan(version)
        ).build();
        List<DbCXPromotion> listDbcxpromotionV=queryDbcxpromotion.find();
        queryDbcxpromotion.close();
        if(listDbcxpromotionV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxpromotionV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxpromotionV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxpromotionV.add(DbCXPromotion.fromJson(item1));
          }
        }

        Query<DbCXSuitBom> queryDbcxsuitbom=XObjectBoxUtils.box_DbCXSuitBom!.query(
            DbCXSuitBom_.version.greaterThan(version)
        ).build();
        List<DbCXSuitBom> listDbcxsuitbomV=queryDbcxsuitbom.find();
        queryDbcxsuitbom.close();
        if(listDbcxsuitbomV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxsuitbomV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxsuitbomV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxsuitbomV.add(DbCXSuitBom.fromJson(item1));
          }
        }

        Query<DbCXMutexPlan> queryDbcxmutexplan=XObjectBoxUtils.box_DbCXMutexPlan!.query(
            DbCXMutexPlan_.version.greaterThan(version)
        ).build();
        List<DbCXMutexPlan> listDbcxmutexplanV=queryDbcxmutexplan.find();
        queryDbcxmutexplan.close();
        if(listDbcxmutexplanV.isNotEmpty){
          //清除数据表id当新数据插入
          String json1=XJsonUtils.obj2Json(listDbcxmutexplanV);
          List<dynamic> list1=XJsonUtils.json2List(json1);
          listDbcxmutexplanV=[];
          for(dynamic item1 in list1){
            item1['id']=0;
            listDbcxmutexplanV.add(DbCXMutexPlan.fromJson(item1));
          }
        }

        //2.删除促销表所有数据
        await XObjectBoxUtils.store?.runInTransaction(TxMode.write,(){
          //XObjectboxUtils.boxStore.removeAllObjects();//注意不能整个数据库清除,有待上传订单或待追平订单

          XObjectBoxUtils.box_DbCXSuitBom!.removeAll();
          XObjectBoxUtils.box_DbCXMutexPlan!.removeAll();
          XObjectBoxUtils.box_DbCXItemBomProduct!.removeAll();
          XObjectBoxUtils.box_DbCXPromotion!.removeAll();
          XObjectBoxUtils.box_DbCXProduct!.removeAll();
          XObjectBoxUtils.box_DBCXOrderProduct!.removeAll();
          XObjectBoxUtils.box_DbCXItemTimed!.removeAll();

          XLogUtils.printLog('---删除促销表所有数据');
        });

        //4.下载促销离线数据
        String baseFileName="CuxiaoDB_${companyId}_";

        if(urls!=null){
          for(int i=0;i<urls.length;i++){

            String filePath='${XTempData.appDocumentsDirectoryPath}/$baseFileName$i';
            //删除旧文件
            XFileUtils.deleteFile(filePath);

            bool isSucceedDownload = false;

            Response downloadResponse= await XHttpUtils.download_sync(
              url: '${urls[i]}',
              savePath: filePath,
            );
            isSucceedDownload=true;

            XLogUtils.printLog("---下载促销文件= $i, isSucceedDownload=$isSucceedDownload");

            if(!isSucceedDownload){
              //失败
              XSharePreferencesUtils.saveInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,0);
              if(statePage is MainWebViewStatePage){
                statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
              }
              return;
            }else{
              //成功
              //1.读取文件
              final int fileIndex=i;

              try{
                List<String> fileLines=await File(filePath).readAsLines();
                XLogUtils.printLog('---促销文件,fileLines=${fileLines.length}');

                await XObjectBoxUtils.store?.runInTransaction(TxMode.write,(){
                  XLogUtils.printLog("---runInTransaction 写入促销文件= $i");
                  String dataType="";
                  while(fileLines.isNotEmpty){
                    String line=fileLines.removeAt(0);

                    //2.写入数据库
                    if (!XStringUtils.isEmpty(line)){
                      if("promotions begin"==line){
                        dataType="promotions";
                      }else if("itemBomProducts begin"==line){
                        dataType="itemBomProducts";
                      }else if("products begin"==line){
                        dataType="products";
                      }else if("itemTimeds begin"==line){
                        dataType="itemTimeds";
                      }else if("orderProducts begin"==line){
                        dataType="orderProducts";
                      }else if("suitBoms begin"==line){
                        dataType="suitBoms";
                      }else if("mutexPlans begin"==line){
                        dataType="mutexPlans";
                      }else if(!line.startsWith("{") && line.contains("end")){
                        dataType="";
                      }else if(line.startsWith("{")){

                        Map<String, dynamic> mapItem = XJsonUtils.json2Map(line);

                        if("promotions"==dataType){
                          DbCXPromotion item=DbCXPromotion();
                          item.planId= '${mapItem['planId']}';
                          item.projectId= '${mapItem['projectId']}';
                          item.promotionJson= mapItem['promotionJson']??'';
                          item.beginDate= '${mapItem['beginDate']}';
                          item.endDate= '${mapItem['endDate']}';
                          item.planType= '${mapItem['planType']}';
                          item.version=version;

                          // if('P002'==item.planType){
                          //   tempCount+=1;
                          //   XLogUtils.printLog('---tempCount=$tempCount');
                          // }

                          //对比增量数据
                          bool isHas=false;
                          for (DbCXPromotion iitem in listDbcxpromotionV){
                            if (iitem.projectId==item.projectId){
                              if (iitem.version>item.version){
                                isHas=true;
                              }
                            }
                          }

                          if(!isHas){
                            //不含有,添加
                            XObjectBoxUtils.box_DbCXPromotion!.put(item);
                          }

                        }else if("itemBomProducts"==dataType){
                          DbCXItemBomProduct item=DbCXItemBomProduct();
                          item.bomId= '${mapItem['bomId']}';
                          item.giftMustQty= '${mapItem['giftMustQty']??'0'}';
                          item.giftMustSel= '${mapItem['giftMustSel']??'0'}';
                          item.itemId= '${mapItem['itemId']}';
                          item.specId= '${mapItem['specId']}';
                          item.version=version;

                          //对比增量数据
                          if(!listDbcxitembomproductV.contains(item)){
                            //不含有则添加

                            //判断商品规格表是否存在,存在则添加,否则查无商品
                            Query<BeanOfflineDBGoodSpec> querySpec=XObjectBoxUtils.goodSpecBox!
                                .query(BeanOfflineDBGoodSpec_.specId.equals(item.specId??''))
                                .build();
                            List<BeanOfflineDBGoodSpec> listSpec=querySpec.find();
                            if(listSpec.isNotEmpty){
                              XObjectBoxUtils.box_DbCXItemBomProduct!.put(item);
                            }
                            querySpec.close();

                          }

                        }else if("products"==dataType){

                          //适用增量更新,因此平铺planid
                          List<dynamic> planIds=mapItem['planIds']??[];
                          Set<String> setPlanid={};
                          for(dynamic iitem in planIds){
                            setPlanid.add('$iitem');
                          }

                          for(String planid in setPlanid){
                            DbCXProduct item=DbCXProduct();
                            item.excl= mapItem['excl']??false;
                            item.planIdEach=planid;
                            item.productType= '${mapItem['productType']}';
                            item.typeId= '${mapItem['typeId']}';
                            item.parentId= '${mapItem['parentId']}';
                            item.version=version;
                            //对比增量数据
                            if(!listDbcxproductV.contains(item)){
                              //不含有,添加
                              XObjectBoxUtils.box_DbCXProduct!.put(item);
                            }
                          }

                        }else if("itemTimeds"==dataType){
                          DbCXItemTimed item=DbCXItemTimed();
                          item.itemId= '${mapItem['itemId']}';
                          item.leftLimitNumPerDay= '${mapItem['leftLimitNumPerDay']}';
                          item.leftTotalLimitNum='${mapItem['leftTotalLimitNum']}';
                          item.limitNumPerDay='${mapItem['limitNumPerDay']}';
                          item.limitPurchases= '${mapItem['limitPurchases']}';
                          item.planId= '${mapItem['planId']}';
                          item.specId= '${mapItem['specId']}';
                          item.specialPrice= '${mapItem['specialPrice']}';
                          item.totalLimitNum= '${mapItem['totalLimitNum']}';
                          item.version=version;

                          //对比增量数据
                          if(!listDbcxitemtimedV.contains(item)){
                            //不含有,添加
                            XObjectBoxUtils.box_DbCXItemTimed!.put(item);
                          }

                        }else if("orderProducts"==dataType){
                          DBCXOrderProduct item=DBCXOrderProduct();
                          item.excl= mapItem['excl']??false;
                          item.planId= '${mapItem['planId']}';
                          item.productType= '${mapItem['productType']}';
                          item.typeId= '${mapItem['typeId']}';
                          item.parentId= '${mapItem['parentId']}';
                          item.version=version;

                          //对比增量数据
                          if(!listDbcxorderproductV.contains(item)){
                            //不含有,添加
                            XObjectBoxUtils.box_DBCXOrderProduct!.put(item);
                          }

                        }else if("suitBoms"==dataType){
                          DbCXSuitBom item=DbCXSuitBom();
                          item.planId= '${mapItem['planId']}';
                          item.bomId= '${mapItem['bomId']}';
                          item.version=version;

                          //对比增量数据
                          if(!listDbcxsuitbomV.contains(item)){
                            //不含有,添加
                            XObjectBoxUtils.box_DbCXSuitBom!.put(item);
                          }
                        }else if("mutexPlans"==dataType){
                          DbCXMutexPlan item=DbCXMutexPlan();
                          item.planId= '${mapItem['planId']}';
                          item.mutexPlanId= '${mapItem['mutexPlanId']}';
                          item.version=version;

                          //对比增量数据
                          if(!listDbcxmutexplanV.contains(item)){
                            //不含有,添加
                            XObjectBoxUtils.box_DbCXMutexPlan!.put(item);
                          }
                        }
                      }
                    }

                  }
                });


              }catch (e){
                XLogUtils.printLog('---写入报错: $e');
                XSharePreferencesUtils.saveInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,0);
                if(statePage is MainWebViewStatePage){
                  statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
                }
                return;
              }

              XLogUtils.printLog("---写入促销文件: $fileIndex");

            }
          }
        }


        //5.重新添加增量数据
        await XObjectBoxUtils.store?.runInTransaction(TxMode.write,(){
          if(listDbcxsuitbomV.isNotEmpty){
            XObjectBoxUtils.box_DbCXSuitBom!.putMany(listDbcxsuitbomV);
          }
          if(listDbcxmutexplanV.isNotEmpty){
            XObjectBoxUtils.box_DbCXMutexPlan!.putMany(listDbcxmutexplanV);
          }
          if(listDbcxitembomproductV.isNotEmpty){
            XObjectBoxUtils.box_DbCXItemBomProduct!.putMany(listDbcxitembomproductV);
          }
          if(listDbcxpromotionV.isNotEmpty){
            XObjectBoxUtils.box_DbCXPromotion!.putMany(listDbcxpromotionV);
          }
          if(listDbcxproductV.isNotEmpty){
            XObjectBoxUtils.box_DbCXProduct!.putMany(listDbcxproductV);
          }
          if(listDbcxorderproductV.isNotEmpty){
            XObjectBoxUtils.box_DBCXOrderProduct!.putMany(listDbcxorderproductV);
          }
          if(listDbcxitemtimedV.isNotEmpty){
            XObjectBoxUtils.box_DbCXItemTimed!.putMany(listDbcxitemtimedV);
          }
          XLogUtils.printLog("---重新添加增量促销数据");
        });

        //6.成功完成通知
        XLogUtils.printLog("---离线促销数据处理完成通知");
        XSharePreferencesUtils.saveInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,version);
        if(statePage is MainWebViewStatePage){
          statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','true'));
        }
      }catch(e){
        XLogUtils.printLog('---下载促销报错:$e');
        //
        XSharePreferencesUtils.saveInt(RBConfigs.SP_offlineDBCuXiaoVersion2+companyId,0);
        if(statePage is MainWebViewStatePage){
          statePage.runJSFunction(statePage.jsFunction_getAppValue('downloadOfflineDBPromotionFileUrl','false'));
        }

      }
    });

  }


  /*
    5.1.清除促销规则表projectId
    如何处理促销方案移除一个规则，例如方案有规则A、B、C，移除B规则
    解决方案：
    1、删除方案里的b规则
    2、查询其他方案是否拥有b规则？有忽略，没有则代表规则已经失效，清空促销规则相关的表数据。
    */
  static void _handleDbCXPromotionOldVersion(
      String projectId,
      Box<DbCXPromotion> boxDbcxpromotion,
      Box<DbCXItemTimed> boxDbcxitemtimed,
      Box<DBCXOrderProduct> boxDbcxorderproduct,
      Box<DbCXProduct> boxDbcxproduct,
      Box<DbCXSuitBom> boxDbcxsuitbom,
      Box<DbCXMutexPlan> boxDbcxmutexplan,
      int version
      ){
    //旧数据
    Query<DbCXPromotion> queryDbcxpromotionOld=boxDbcxpromotion.query(
        DbCXPromotion_.projectId.equals(projectId).and(DbCXPromotion_.version.lessThan(version))
    ).build();
    List<DbCXPromotion> listDbcxpromotionOld=queryDbcxpromotionOld.find();
    queryDbcxpromotionOld.close();
    //当前数据
    Query<DbCXPromotion> queryDbcxpromotion=boxDbcxpromotion.query(
        DbCXPromotion_.projectId.equals(projectId).and(DbCXPromotion_.version.equals(version))
    ).build();
    List<DbCXPromotion> listDbcxpromotion=queryDbcxpromotion.find();
    queryDbcxpromotion.close();

    //1.过滤出删除的planId
    Set<String> planidsDel={};
    for(DbCXPromotion item in listDbcxpromotionOld){
      if (!listDbcxpromotion.contains(item)){
        //不含有,则是本次删除的planId
        planidsDel.add(item.planId??'');
      }
    }

    //2.删除旧projectId促销规则表数据
    if(listDbcxpromotionOld.isNotEmpty){
      List<int> ids=[];
      for(DbCXPromotion item in listDbcxpromotionOld){
        ids.add(item.id);
      }
      boxDbcxpromotion.removeMany(ids);
    }

    //3.循环planIds，判断其他方案是否用存在该planid？有忽略，没有则代表规则已经失效，清空促销规则相关的表数据。
    for(String planId in planidsDel){
      Query<DbCXPromotion> queryPromotion=boxDbcxpromotion.query(
          DbCXPromotion_.projectId.notEquals(projectId).and(DbCXPromotion_.planId.equals(planId))
      ).build();
      List<DbCXPromotion> listPromotion=queryPromotion.find();
      queryPromotion.close();
      if(listPromotion.isEmpty){
        //不存在则为失效,清除失效planId
        _cleanProjectIdPlanId(planId,version,boxDbcxitemtimed,boxDbcxorderproduct,boxDbcxproduct,boxDbcxsuitbom,boxDbcxmutexplan);
      }
    }

  }

  //清除projectId对应的促销规则表的失效planId所关联表的数据
  static void _cleanProjectIdPlanId(
      String planId,
      int version,
      Box<DbCXItemTimed> boxDbcxitemtimed,
      Box<DBCXOrderProduct> boxDbcxorderproduct,
      Box<DbCXProduct> boxDbcxproduct,
      Box<DbCXSuitBom> boxDbcxsuitbom,
      Box<DbCXMutexPlan> boxDbcxmutexplan
      ){

    Query<DbCXItemTimed> queryItemtimed=boxDbcxitemtimed.query(
        DbCXItemTimed_.planId.equals(planId).and(DbCXItemTimed_.version.lessThan(version))
    ).build();
    List<DbCXItemTimed> listItemtimed=queryItemtimed.find();
    if (listItemtimed.isNotEmpty){
      List<int> ids=[];
      for(DbCXItemTimed item in listItemtimed){
        ids.add(item.id);
      }
      boxDbcxitemtimed.removeMany(ids);
    }
    queryItemtimed.close();

    Query<DBCXOrderProduct> queryDbcxorderproduct=boxDbcxorderproduct.query(
        DBCXOrderProduct_.planId.equals(planId).and(DBCXOrderProduct_.version.lessThan(version))
    ).build();
    List<DBCXOrderProduct> listDbcxorderproduct=queryDbcxorderproduct.find();
    if (listDbcxorderproduct.isNotEmpty){
      List<int> ids=[];
      for(DBCXOrderProduct item in listDbcxorderproduct){
        ids.add(item.id);
      }
      boxDbcxorderproduct.removeMany(ids);
    }
    queryDbcxorderproduct.close();

    Query<DbCXProduct> queryDbcxproduct=boxDbcxproduct.query(
        DbCXProduct_.planIdEach.equals(planId).and(DbCXProduct_.version.lessThan(version))
    ).build();
    List<DbCXProduct> listDbcxproduct=queryDbcxproduct.find();
    if (listDbcxproduct.isNotEmpty){
      List<int> ids=[];
      for(DbCXProduct item in listDbcxproduct){
        ids.add(item.id);
      }
      boxDbcxproduct.removeMany(ids);
    }
    queryDbcxproduct.close();

    Query<DbCXSuitBom> queryDbcxsuitbom=boxDbcxsuitbom.query(
        DbCXSuitBom_.planId.equals(planId).and(DbCXSuitBom_.version.lessThan(version))
    ).build();
    List<DbCXSuitBom> listDbcxsuitbom=queryDbcxsuitbom.find();
    if (listDbcxsuitbom.isNotEmpty){
      List<int> ids=[];
      for(DbCXSuitBom item in listDbcxsuitbom){
        ids.add(item.id);
      }
      boxDbcxsuitbom.removeMany(ids);
    }
    queryDbcxsuitbom.close();

    Query<DbCXMutexPlan> queryDbcxmutexplan=boxDbcxmutexplan.query(
        DbCXMutexPlan_.planId.equals(planId).and(DbCXMutexPlan_.version.lessThan(version))
    ).build();
    List<DbCXMutexPlan> listDbcxmutexplan=queryDbcxmutexplan.find();
    if (listDbcxmutexplan.isNotEmpty){
      List<int> ids=[];
      for(DbCXMutexPlan item in listDbcxmutexplan){
        ids.add(item.id);
      }
      boxDbcxmutexplan.removeMany(ids);
    }
    queryDbcxmutexplan.close();

  }

//增量更新删除
  static void _updateGoodItems_del(XPageState statePage,List<String> items,int version){


    for(String itemId in items){

      Query<BeanOfflineDBGood> queryBeanofflinedbgoods=XObjectBoxUtils.goodBox!.query(
          BeanOfflineDBGood_.itemId.equals(itemId)
      ).order(BeanOfflineDBGood_.version,flags: Order.descending)
          .build();
      List<BeanOfflineDBGood> listBeanofflinedbgoods=queryBeanofflinedbgoods.find();

      if(listBeanofflinedbgoods.isNotEmpty){
        BeanOfflineDBGood versionItem=listBeanofflinedbgoods.first;
        if(version>versionItem.version){
          versionItem.version=version;
          versionItem.isDel=true;
          XObjectBoxUtils.goodBox!.put(versionItem);
          queryBeanofflinedbgoods.close();

          Query<BeanOfflineDBGoodSpec> queryBeanofflinedbgoodsSpec=XObjectBoxUtils.goodSpecBox!
              .query(BeanOfflineDBGoodSpec_.itemId.equals(versionItem.itemId??''))
              .build();
          List<BeanOfflineDBGoodSpec> listSpecLess=queryBeanofflinedbgoodsSpec.find();

          for(BeanOfflineDBGoodSpec spec in listSpecLess){
            spec.isDel=true;
          }
          XObjectBoxUtils.goodSpecBox!.putMany(listSpecLess);
          queryBeanofflinedbgoodsSpec.close();
        }
      }

    }

    if(statePage is MainWebViewStatePage){
      statePage.runJSFunction(statePage.jsFunction_getAppValue('h5webSocketUpdateGoodItemsDB','true'));
    }

  }

  //增量更新商品数据
  static void _update_goods_by_ItemIds(XPageState statePage,List<String> itemIds) async{
    Response_updateGoodItemsDB? response= await RBBaseApi.updateGoodItemsDB(itemIds:itemIds);

    if (response==null || "200"!=response.code
    ){
      //通知失败
      String msg="增量更新商品失败";
      if(statePage is MainWebViewStatePage){
        statePage.runJSFunction(statePage.jsFunction_getAppValue('h5webSocketUpdateGoodItemsDB','false'));
      }

      return;
    }


    List<dynamic>? data=response.data;
    if (data==null || data.isEmpty){
      //如果请求返回数据空, 不做任何处理
    }else{
      //判断是否同时有更新和删除下架情况

      for(dynamic apiItem1 in data){
        int version=int.tryParse('${apiItem1['version']??0}')??0;
        XLogUtils.printLog('---增量,versionObj=${apiItem1['version']},version=$version');

        int lineId=int.tryParse('${apiItem1['lineId']??0}')??0;
        String itemId= apiItem1['itemId']??'';
        String itemName= apiItem1['itemName']??'';

        Query<BeanOfflineDBGood> queryBeanofflinedbgoods2=XObjectBoxUtils.goodBox!.query(
            BeanOfflineDBGood_.itemId.equals(itemId).and(BeanOfflineDBGood_.version.greaterOrEqual(version))
        ).build();
        List<BeanOfflineDBGood> listBeanofflinedbgoods2=queryBeanofflinedbgoods2.find();
        queryBeanofflinedbgoods2.close();
        if(listBeanofflinedbgoods2.isNotEmpty){
          XLogUtils.printLog('---存在新版本,当前增量忽略');
          continue;
        }

        //
        Query<BeanOfflineDBGood> queryBeanofflinedbgoods=XObjectBoxUtils.goodBox!.query(
            BeanOfflineDBGood_.itemId.equals(itemId).and(BeanOfflineDBGood_.version.lessOrEqual(version))
        ).build();
        List<BeanOfflineDBGood> listBeanofflinedbgoods=queryBeanofflinedbgoods.find();
        queryBeanofflinedbgoods.close();

        if(listBeanofflinedbgoods.isNotEmpty){
          //新版本,修改, 先删除旧版
          XLogUtils.printLog('---增量新版本,先删除旧版');

          List<int> ids=[];
          for(BeanOfflineDBGood iitem in listBeanofflinedbgoods){
            iitem.shelfTime.clear();
            ids.add(iitem.id);
          }
          XObjectBoxUtils.goodBox!.removeMany(ids);

          //删除规格
          Query<BeanOfflineDBGoodSpec> queryBeanofflinedbgoodsSpec=XObjectBoxUtils.goodSpecBox!
              .query(BeanOfflineDBGoodSpec_.itemId.equals(itemId))
              .build();
          List<BeanOfflineDBGoodSpec> listSpecLess=queryBeanofflinedbgoodsSpec.find();
          queryBeanofflinedbgoodsSpec.close();
          if(listSpecLess.isNotEmpty){
            List<int> ids1=[];
            for(BeanOfflineDBGoodSpec iitem in listSpecLess){
              ids1.add(iitem.id);
            }
            XObjectBoxUtils.goodSpecBox!.removeMany(ids1);
          }

        }

        //新增
        BeanOfflineDBGood newItem= BeanOfflineDBGood();
        //
        newItem.itemTypefCode= apiItem1['itemTypefCode']??'';
        newItem.itemCode=apiItem1["itemCode"]??"";
        newItem.itemName=itemName;
        newItem.itemId=itemId;
        newItem.specId=itemId;
        newItem.specType='${apiItem1["specType"]??"0"}';
        newItem.version=version;
        newItem.lineId=lineId;

        if (!XStringUtils.isEmpty(newItem.itemName)){
          newItem.pinyin= XPinyinUtils.getShortPinyin(newItem.itemName??'');
        }

        //简化版
        Map<String,dynamic> itemSimple={};

        List<dynamic> specList=apiItem1['specList']??[];
        if (specList.isNotEmpty){
          //规格的sku
          StringBuffer sbSku=StringBuffer();
          StringBuffer sbAttachBarcode=StringBuffer();

          for (dynamic arrItemObj in specList){
            Map<String,dynamic> objSpec=arrItemObj;
            //XLogUtils.printLog("----indexSpec="+indexSpec);
            //sku
            String? skuBarcode= objSpec['skuBarcode'];
            if(!XStringUtils.isEmpty(skuBarcode)){
              sbSku.write('$skuBarcode,');
            }
            //sku
            String? attachBarcode= objSpec['attachBarcode'];
            if(!XStringUtils.isEmpty(attachBarcode)){
              sbAttachBarcode.write('$attachBarcode,');
            }

            //是否启用负库存
            itemSimple['isNegativeStock']=objSpec['isNegativeStock'];

            //规格级别表
            BeanOfflineDBGoodSpec specItem=BeanOfflineDBGoodSpec();
            specItem.itemId= objSpec['itemId']??'';
            specItem.specId= objSpec['specId']??'';
            specItem.specName= objSpec['specName']??'';
            specItem.skuBarcode= objSpec['skuBarcode']??'';
            specItem.attachBarcode= objSpec['attachBarcode']??'';
            specItem.json=XJsonUtils.obj2Json(objSpec);
            specItem.version=version;
            XObjectBoxUtils.saveBeanOfflineDBGoodSpec(specItem);
          }
          if(sbSku.isNotEmpty){
            newItem.skuBarcode=sbSku.toString();
            if(newItem.skuBarcode!.endsWith(',')){
              newItem.skuBarcode=newItem.skuBarcode!.substring(0,newItem.skuBarcode!.length-1);
            }
          }
          if(sbAttachBarcode.isNotEmpty){
            newItem.attachBarcode=sbAttachBarcode.toString();
            if(newItem.attachBarcode!.endsWith(',')){
              newItem.attachBarcode=newItem.attachBarcode!.substring(0,newItem.attachBarcode!.length-1);
            }
          }

        }

        newItem.json=XJsonUtils.obj2Json(apiItem1);

        //是否标识为删除下架
        bool remove= false;
        dynamic removeObj = apiItem1['remove'];
        if(removeObj!=null){
          try{
            remove=removeObj;
          }catch(e){
            //
          }
        }
        newItem.isDel=remove;


        //上架有效期时间
        int shelfValidityStart_long=0;
        int shelfValidityEnd_long=0;
        try{
          int? onShelfValidityPeriodBeginD=int.tryParse('${apiItem1["onShelfValidityPeriodBegin"]??0}');
          int? onShelfValidityPeriodEndD=int.tryParse('${apiItem1["onShelfValidityPeriodEnd"]??0}');

          //上架有效期开始时间
          if(onShelfValidityPeriodBeginD!=null && onShelfValidityPeriodBeginD>0){
            String onShelfValidityPeriodBegin=XDateUtils.getStringTimeFormat(dateTime: XDateUtils.getDateTimeWithMilliseconds(onShelfValidityPeriodBeginD),format: XDateUtils.formatTimeDefault3);
            onShelfValidityPeriodBegin='$onShelfValidityPeriodBegin 00:00:00';
            DateTime? onShelfValidityPeriodBegin_d=XDateUtils.getDateTimeWithString(onShelfValidityPeriodBegin);
            if(onShelfValidityPeriodBegin_d!=null){
              shelfValidityStart_long=XDateUtils.getTime_ms(dateTime: onShelfValidityPeriodBegin_d);
            }

          }

          //上架有效期结束时间
          if(onShelfValidityPeriodEndD!=null && onShelfValidityPeriodEndD>0){
            String onShelfValidityPeriodEnd=XDateUtils.getStringTimeFormat(dateTime: XDateUtils.getDateTimeWithMilliseconds(onShelfValidityPeriodEndD),format: XDateUtils.formatTimeDefault3);
            onShelfValidityPeriodEnd='$onShelfValidityPeriodEnd 23:59:59';
            DateTime? onShelfValidityPeriodEnd_d=XDateUtils.getDateTimeWithString(onShelfValidityPeriodEnd);
            if(onShelfValidityPeriodEnd_d!=null){
              shelfValidityEnd_long=XDateUtils.getTime_ms(dateTime: onShelfValidityPeriodEnd_d);
            }

          }

        }catch(e){
          XLogUtils.printLog('$e');
        }finally{
          //上架有效期开始时间
          newItem.shelfValidityStart=shelfValidityStart_long;
          newItem.shelfValidityEnd=shelfValidityEnd_long;
          //
          XLogUtils.printLog('---增量,shelfValidityStart=$shelfValidityStart_long');
          XLogUtils.printLog('---增量,shelfValidityEnd=$shelfValidityEnd_long');
        }

        //上架有效期时间段
        bool isHasShelfTime=false;
        try{
          String? onShelfTime=apiItem1["onShelfTime"];
          if(!XStringUtils.isEmpty(onShelfTime)){
            XLogUtils.printLog('---增量,onShelfTime=$onShelfTime');
            //多个时间段
            List<String> arr=onShelfTime!.split(';');
            for(String mItem in arr){
              //开始时间和结束时间
              if(!XStringUtils.isEmpty(mItem) && mItem.contains('~')){
                List<String> start_end=mItem.split('~');

                int shelfTimeStart=0;
                int shelfTimeEnd=0;
                String start_Str=start_end[0];
                String end_Str=start_end[1];

                //小时,分钟
                if(!XStringUtils.isEmpty(start_Str)&& start_Str.contains(':')){
                  List<String> h_m=start_Str.split(':');
                  int hour=int.tryParse(h_m[0])??0;
                  int min=int.tryParse(h_m[1])??0;
                  shelfTimeStart=hour*60*60*1000+min*60*1000;
                }
                if(!XStringUtils.isEmpty(end_Str)&& end_Str.contains(':')){
                  List<String> h_m=end_Str.split(':');
                  int hour=int.tryParse(h_m[0])??0;
                  int min=int.tryParse(h_m[1])??0;
                  shelfTimeEnd=hour*60*60*1000+min*60*1000;
                }

                if(shelfTimeEnd>shelfTimeStart){
                  isHasShelfTime=true;
                  newItem.shelfTime.add(BeanShelfTime(shelfTimeStart:shelfTimeStart,shelfTimeEnd: shelfTimeEnd));
                }

              }
            }

          }

        }catch(e){
          XLogUtils.printLog('$e');
        }finally{
          //不能为null
          if(!isHasShelfTime){
            newItem.shelfTime.add(BeanShelfTime(shelfTimeStart:0,shelfTimeEnd: 0));
          }
        }

        //简化版
        itemSimple['itemName']=apiItem1['itemName'];
        itemSimple['itemId']=apiItem1['itemId'];
        itemSimple['unit']=apiItem1['unit'];
        itemSimple['dealPrice']=apiItem1['dealPrice'];
        itemSimple['specType']='${apiItem1["specType"]??"0"}';
        itemSimple['bomType']=apiItem1['bomType'];
        itemSimple['hasLabel']=apiItem1['hasLabel'];
        itemSimple['isBatch']=apiItem1['isBatch'];
        itemSimple['isBom']=apiItem1['isBom'];
        itemSimple['isStock']=apiItem1['isStock'];//是否启用库存管理
        itemSimple['isUniqueCode']=apiItem1['isUniqueCode'];
        itemSimple['imageUrlFull']=apiItem1['imageUrlFull'];
        newItem.jsonSimple=XJsonUtils.obj2Json(itemSimple);

        XObjectBoxUtils.saveBeanOfflineDBGood(newItem);

      }

    }

    if(statePage is MainWebViewStatePage){
      statePage.runJSFunction(statePage.jsFunction_getAppValue('h5webSocketUpdateGoodItemsDB','true'));
    }

  }



//离线文件写入数据库(全量的统一用外部的版本号)
  static void _saveToDB(
      List<String> lines,
      int version
      ){

    int totalSize=lines.length;
    //
    while(lines.isNotEmpty){
      String line=lines.removeAt(0);
      int tempSize=lines.length;

      Map<String, dynamic> beanLineItem=XJsonUtils.json2Map(line);

      //商品级别表
      BeanOfflineDBGood item=BeanOfflineDBGood();
      //
      item.itemTypefCode=beanLineItem["itemTypefCode"]??"";
      item.itemCode=beanLineItem["itemCode"]??"";
      item.itemName=beanLineItem["itemName"]??"";
      item.itemId=beanLineItem["itemId"]??"";
      item.specId=beanLineItem["itemId"]??"";
      item.specType='${beanLineItem["specType"]??"0"}';
      item.version=version;//全量的统一用外部的版本号
      item.lineId=int.tryParse('${beanLineItem["lineId"]??0}')??0;
      item.pinyin='';
      //
      if (!XStringUtils.isEmpty(item.itemName)){
        try{
          item.pinyin= XPinyinUtils.getShortPinyin(item.itemName!);
        }catch(e){
          //
        }
      }

      if(item.lineId%50==0){
        String progressValue=XNumberUtils.formatDoubleX((1-tempSize/totalSize)*100,n:0);
        XLogUtils.printLog("---read line,totalSize=$totalSize,progressValue=$progressValue%");
      }

      //
      if(version!=0) {
        //逐行对比现有版本,判断是否>=version的,忽略跳过
        Query<BeanOfflineDBGood> queryBeanofflinedbgoods2=XObjectBoxUtils.goodBox!
            .query(BeanOfflineDBGood_.itemId.equals(item.itemId!).and(BeanOfflineDBGood_.version.greaterOrEqual(item.version)))
            .build();
        List<BeanOfflineDBGood> listGreaterorequal=queryBeanofflinedbgoods2.find();
        queryBeanofflinedbgoods2.close();
        if(listGreaterorequal.isNotEmpty){
          continue;
        }
      }

      //规格级别
      List<dynamic> specList=beanLineItem["specList"]??[];
      StringBuffer sbSku=StringBuffer();
      StringBuffer sbAttachBarcode=StringBuffer();

      //简化版
      Map<String,dynamic> itemSimple={};

      //
      for(dynamic obj_spec in specList){
        //sku
        String? skuBarcode=obj_spec['skuBarcode'];
        if(!XStringUtils.isEmpty(skuBarcode)){
          sbSku.write("$skuBarcode,");
        }
        String? attachBarcode=obj_spec['attachBarcode'];
        if(!XStringUtils.isEmpty(attachBarcode)){
          sbAttachBarcode.write("$attachBarcode,");
        }

        //是否启用负库存
        itemSimple['isNegativeStock']=obj_spec['isNegativeStock'];

        //规格
        BeanOfflineDBGoodSpec specItem=BeanOfflineDBGoodSpec();
        specItem.itemId=obj_spec['itemId']??'';
        specItem.specId=obj_spec['specId']??'';
        specItem.specName= obj_spec['specName']??'';
        specItem.skuBarcode= obj_spec['skuBarcode']??'';
        specItem.attachBarcode= obj_spec['attachBarcode']??'';
        specItem.json=XJsonUtils.obj2Json(obj_spec);

        specItem.version=item.version;
        //保存
        XObjectBoxUtils.saveBeanOfflineDBGoodSpec(specItem);

      }

      if(sbSku.isNotEmpty){
        item.skuBarcode=sbSku.toString();
        if(item.skuBarcode!.endsWith(',')){
          item.skuBarcode=item.skuBarcode!.substring(0,item.skuBarcode!.length-1);
        }
      }
      if(sbAttachBarcode.isNotEmpty){
        item.attachBarcode=sbAttachBarcode.toString();
        if(item.attachBarcode!.endsWith(',')){
          item.attachBarcode=item.attachBarcode!.substring(0,item.attachBarcode!.length-1);
        }
      }
      item.json=line;


      //上架有效期时间
      int shelfValidityStart_long=0;
      int shelfValidityEnd_long=0;
      try{
        int? onShelfValidityPeriodBeginD=int.tryParse('${beanLineItem["onShelfValidityPeriodBegin"]??0}');
        int? onShelfValidityPeriodEndD=int.tryParse('${beanLineItem["onShelfValidityPeriodEnd"]??0}');

        //上架有效期开始时间
        if(onShelfValidityPeriodBeginD!=null && onShelfValidityPeriodBeginD>0){
          String onShelfValidityPeriodBegin=XDateUtils.getStringTimeFormat(dateTime: XDateUtils.getDateTimeWithMilliseconds(onShelfValidityPeriodBeginD),format: XDateUtils.formatTimeDefault3);
          onShelfValidityPeriodBegin='$onShelfValidityPeriodBegin 00:00:00';

          //XLogUtils.printLog('---onShelfValidityPeriodBegin=$onShelfValidityPeriodBegin');

          DateTime? onShelfValidityPeriodBegin_d=XDateUtils.getDateTimeWithString(onShelfValidityPeriodBegin);
          if(onShelfValidityPeriodBegin_d!=null){
            shelfValidityStart_long=XDateUtils.getTime_ms(dateTime: onShelfValidityPeriodBegin_d);
          }

        }

        //上架有效期结束时间
        if(onShelfValidityPeriodEndD!=null && onShelfValidityPeriodEndD>0){
          String onShelfValidityPeriodEnd=XDateUtils.getStringTimeFormat(dateTime: XDateUtils.getDateTimeWithMilliseconds(onShelfValidityPeriodEndD),format: XDateUtils.formatTimeDefault3);
          onShelfValidityPeriodEnd='$onShelfValidityPeriodEnd 23:59:59';
          //XLogUtils.printLog('---onShelfValidityPeriodEnd=$onShelfValidityPeriodEnd');

          DateTime? onShelfValidityPeriodEnd_d=XDateUtils.getDateTimeWithString(onShelfValidityPeriodEnd);
          if(onShelfValidityPeriodEnd_d!=null){
            shelfValidityEnd_long=XDateUtils.getTime_ms(dateTime: onShelfValidityPeriodEnd_d);
          }

        }

      }catch(e){
        XLogUtils.printLog('--上架有效期:$e,${beanLineItem["onShelfValidityPeriodBegin"]},${beanLineItem["onShelfValidityPeriodEnd"]}');
      }finally{
        //上架有效期开始时间
        item.shelfValidityStart=shelfValidityStart_long;
        item.shelfValidityEnd=shelfValidityEnd_long;
      }

      //上架有效期时间段
      bool isHasShelfTime=false;
      try{
        String? onShelfTime=beanLineItem["onShelfTime"];
        if(!XStringUtils.isEmpty(onShelfTime)){
          //多个时间段
          List<String> arr=onShelfTime!.split(';');
          for(String mItem in arr){
            //开始时间和结束时间
            if(!XStringUtils.isEmpty(mItem) && mItem.contains('~')){
              List<String> start_end=mItem.split('~');

              int shelfTimeStart=0;
              int shelfTimeEnd=0;
              String start_Str=start_end[0];
              String end_Str=start_end[1];

              //小时,分钟
              if(!XStringUtils.isEmpty(start_Str)&& start_Str.contains(':')){
                List<String> h_m=start_Str.split(':');
                int hour=int.tryParse(h_m[0])??0;
                int min=int.tryParse(h_m[1])??0;
                shelfTimeStart=hour*60*60*1000+min*60*1000;
              }
              if(!XStringUtils.isEmpty(end_Str)&& end_Str.contains(':')){
                List<String> h_m=end_Str.split(':');
                int hour=int.tryParse(h_m[0])??0;
                int min=int.tryParse(h_m[1])??0;
                shelfTimeEnd=hour*60*60*1000+min*60*1000;
              }

              if(shelfTimeEnd>shelfTimeStart){
                isHasShelfTime=true;
                item.shelfTime.add(BeanShelfTime(shelfTimeStart:shelfTimeStart,shelfTimeEnd: shelfTimeEnd));
              }

            }
          }

        }

      }catch(e){
        XLogUtils.printLog('---上架时间段:$e');
      }finally{
        //不能为null
        //XLogUtils.printLog('---isHasShelfTime:$isHasShelfTime');
        if(!isHasShelfTime){
          item.shelfTime.add(BeanShelfTime(shelfTimeStart:0,shelfTimeEnd: 0));
        }
      }

      //简化版
      itemSimple['itemName']=beanLineItem['itemName'];
      itemSimple['itemId']=beanLineItem['itemId'];
      itemSimple['unit']=beanLineItem['unit'];
      itemSimple['dealPrice']=beanLineItem['dealPrice'];
      itemSimple['specType']='${beanLineItem["specType"]??"0"}';
      itemSimple['bomType']=beanLineItem['bomType'];
      itemSimple['hasLabel']=beanLineItem['hasLabel'];
      itemSimple['isBatch']=beanLineItem['isBatch'];
      itemSimple['isBom']=beanLineItem['isBom'];
      itemSimple['isStock']=beanLineItem['isStock'];//是否启用库存管理
      itemSimple['isUniqueCode']=beanLineItem['isUniqueCode'];
      itemSimple['imageUrlFull']=beanLineItem['imageUrlFull'];
      item.jsonSimple=XJsonUtils.obj2Json(itemSimple);

      //保存
      XObjectBoxUtils.saveBeanOfflineDBGood(item);
      sbSku.clear();
    }

    XLogUtils.printLog("---_saveToDB完成!");
  }





}
